
from typing import Callable, Optional
from typing import Union, Tuple




class sCc9dPkg:
    from_port: int  # 源端口号，发送方的端口号
    to_port: int  # 目的端口号，接收方的端口号
    remote_addr: int  # 远端地址，对于收到的包，是发送方地址，对于要发送的包，是接收方地址
    datas: Optional[bytes] = None  # 数据部分，最大64字节，默认值为None
    _dir: str = "s"  # 方向，"s"表示发送，"r"表示接收


    @classmethod
    def fromCode(cls, from_port: int, chhol_code:str) -> Union[str, 'sCc9dPkg']:
        """
        从Chhol代码格式的字符串创建一个sCc9dPkg实例
        格式示例: "000C.112: 12 23 A1 56 /H |255"        
        参数:
            from_port: 源端口号   
            chhol_code: Chhol代码格式的字符串     
        返回:
            成功时返回包对象
            失败时返回错误信息
        """
        if from_port > 100:
            return f"源端口值({from_port})超出范围"
        
        # 首先解析地址
        destination_spec = chhol_code.find(':')
        if destination_spec == -1:
            return "没有找到':'"
        
        desc_str = chhol_code[:destination_spec]
        dot_spec = desc_str.find('.')
        if dot_spec == -1:
            return "没有找到'.'"
        
        # 获取目标地址和端口
        try:
            addr = int(desc_str[:dot_spec], 16)
            if addr > 0xFFFF:
                return f"目标地址超出范围({addr})，应为16位无符号整数。"
        except ValueError:
            return f"目标地址解析失败。({desc_str[:dot_spec]})"        
        try:
            to_port = int(desc_str[dot_spec + 1:])
            if to_port >= 128:
                return f"目标端口值超出范围({to_port})，Chhol的端口都小于128。"
        except ValueError:
            return f"目标端口解析失败。({desc_str[dot_spec + 1:]})"
        
        # 解析数据部分
        data_str = chhol_code[destination_spec + 1:].strip()
        data_bytes, error = cls._str_to_bytes(data_str)
        if error:
            return error
        
        pkg = cls(from_port=from_port, to_port=to_port, remote_addr=addr, datas=data_bytes)
        return pkg
    
    
    @staticmethod
    def _str_to_bytes(s: str) -> Tuple[bytes, str]:
        """将Chhol格式的字符串转换为字节数组"""
        if not s:
            return bytes(), None
        
        if s.startswith('$'):
            text = s[1:]
            for i, char in enumerate(text):
                if ord(char) > 127:  # 非ASCII字符
                    return None, f"只支持ASCII字符，第{i+1}个字符'{char}'是非法字符"
            try:
                return text.encode('ascii'), None
            except UnicodeEncodeError:
                return None, "ASCII编码失败。"
        
        result = bytearray()
        parts = [p for p in s.split() if p]
        
        for part in parts:
            if part.startswith('|'):  # 十进制
                try:
                    value = int(part[1:])
                    if value > 255:
                        return None, f"十进制值超出范围({part})"
                    result.append(value)
                except ValueError:
                    return None, f"按照十进制数据解析失败。({part})"
            
            elif part.startswith('w'):  # 十进制，2字节
                try:
                    value = int(part[1:])
                    if value > 65535:
                        return None, f"十进制值超出范围({part})"
                    result.append(value & 0xFF)
                    result.append((value >> 8) & 0xFF)
                except ValueError:
                    return None, f"按照十进制数据解析为二比特失败。({part})"
            
            elif part.startswith('q'):  # 十进制，4字节
                try:
                    value = int(part[1:])
                    result.append(value & 0xFF)
                    result.append((value >> 8) & 0xFF)
                    result.append((value >> 16) & 0xFF)
                    result.append((value >> 24) & 0xFF)
                except ValueError:
                    return None, f"按照十进制数据解析为四比特失败。({part})"
            
            elif part.startswith('/'):  # ASCII码
                if len(part) != 2:
                    return None, f"只能转换单个字符({part})"
                char = part[1]
                if ord(char) > 127:
                    return None, f"只支持ASCII字符，'{char}'是非法字符"
                result.append(ord(char))
            
            else:  # 十六进制
                hex_str = part
                if len(hex_str) % 2 == 1:
                    hex_str = "0" + hex_str
                
                try:
                    for i in range(0, len(hex_str), 2):
                        value = int(hex_str[i:i+2], 16)
                        result.append(value)
                except ValueError:
                    return None, f"按照十六进制数据解析失败。({part})"
        
        return bytes(result), None
    
    
    

    def __init__(self, from_port: int = 0, to_port: int = 0, remote_addr: int = 0, datas:bytes = None ) -> None:  
        self.from_port = from_port
        self.to_port = to_port
        self.remote_addr = remote_addr
        self.datas = datas

    def asRecv(self) -> None:
        self._dir = "r"
    
    def asSend(self) -> None:
        self._dir = "s"

    def __repr__(self) -> str:
        data_str = ' '.join(f'{byte:02x}' for byte in self.datas)
        if self._dir == "s":
            return f"this.{self.from_port}->{self.remote_addr:04x}.{self.to_port}: {data_str}"
        elif self._dir == "r":
            return f"{self.remote_addr:04x}.{self.from_port}->this.{self.to_port}: {data_str}"
        else:
            return f"remote_addr={self.remote_addr:04x},{self.from_port}->{self.to_port}: {data_str}"  


class CC9DProtocolParser:    
    MAC_SIZE = 5  # from_port (1 byte) + to_port (1 byte) + remote_addr (2 bytes) + end_crc (1 byte)
    MAX_DATA_SIZE = 64
    SEPARATOR = 0x9d
    ESCAPE = 0x9e
    ESC_9D = 0xfe
    ESC_9E = 0xff

    def _printd(self, *args, **kwargs):
        if self._do_print:
            print(*args, **kwargs)

    _Crc_table = bytes([        
        0x00,0x31,0x62,0x53,0xc4,0xf5,0xa6,0x97,0xb9,0x88,0xdb,0xea,0x7d,0x4c,0x1f,0x2e,
        0x43,0x72,0x21,0x10,0x87,0xb6,0xe5,0xd4,0xfa,0xcb,0x98,0xa9,0x3e,0x0f,0x5c,0x6d,
        0x86,0xb7,0xe4,0xd5,0x42,0x73,0x20,0x11,0x3f,0x0e,0x5d,0x6c,0xfb,0xca,0x99,0xa8,
        0xc5,0xf4,0xa7,0x96,0x01,0x30,0x63,0x52,0x7c,0x4d,0x1e,0x2f,0xb8,0x89,0xda,0xeb,
        0x3d,0x0c,0x5f,0x6e,0xf9,0xc8,0x9b,0xaa,0x84,0xb5,0xe6,0xd7,0x40,0x71,0x22,0x13,
        0x7e,0x4f,0x1c,0x2d,0xba,0x8b,0xd8,0xe9,0xc7,0xf6,0xa5,0x94,0x03,0x32,0x61,0x50,
        0xbb,0x8a,0xd9,0xe8,0x7f,0x4e,0x1d,0x2c,0x02,0x33,0x60,0x51,0xc6,0xf7,0xa4,0x95,
        0xf8,0xc9,0x9a,0xab,0x3c,0x0d,0x5e,0x6f,0x41,0x70,0x23,0x12,0x85,0xb4,0xe7,0xd6,
        0x7a,0x4b,0x18,0x29,0xbe,0x8f,0xdc,0xed,0xc3,0xf2,0xa1,0x90,0x07,0x36,0x65,0x54,
        0x39,0x08,0x5b,0x6a,0xfd,0xcc,0x9f,0xae,0x80,0xb1,0xe2,0xd3,0x44,0x75,0x26,0x17,
        0xfc,0xcd,0x9e,0xaf,0x38,0x09,0x5a,0x6b,0x45,0x74,0x27,0x16,0x81,0xb0,0xe3,0xd2,
        0xbf,0x8e,0xdd,0xec,0x7b,0x4a,0x19,0x28,0x06,0x37,0x64,0x55,0xc2,0xf3,0xa0,0x91,
        0x47,0x76,0x25,0x14,0x83,0xb2,0xe1,0xd0,0xfe,0xcf,0x9c,0xad,0x3a,0x0b,0x58,0x69,
        0x04,0x35,0x66,0x57,0xc0,0xf1,0xa2,0x93,0xbd,0x8c,0xdf,0xee,0x79,0x48,0x1b,0x2a,
        0xc1,0xf0,0xa3,0x92,0x05,0x34,0x67,0x56,0x78,0x49,0x1a,0x2b,0xbc,0x8d,0xde,0xef,
        0x82,0xb3,0xe0,0xd1,0x46,0x77,0x24,0x15,0x3b,0x0a,0x59,0x68,0xff,0xce,0x9d,0xac
    ]  ) 
    
    def __init__(self, sendByteCB: Callable[[bytes], bool], recvPkgCB: Callable[[sCc9dPkg], None]):
        # 发送相关程序
        self._sendByteCB = sendByteCB
        self._sendByteCB(bytes([self.SEPARATOR, self.SEPARATOR]))  # 发送起始字节。
        # 下面是接收相关
        self._recv_buffer = bytearray()
        self._recv_in_esc = False
        self._recvPkgCB = recvPkgCB  # 初始化接收回调函数
        if __name__ == "__main__":
            self._do_print = True
            self._printd("CC9D 会输出调试信息")
        else:
            self._do_print = False

        
    
    
    def send(self, pkg: sCc9dPkg) -> None:
        data = self._build(pkg)
        self._sendByteCB(data)
    
    def _build(self, pkg: sCc9dPkg) -> bytes:
        data = bytearray()
        send_crc = 0xff	
        def escape_and_append(byte: int) -> None:
            if byte == self.SEPARATOR:
                data.append(self.ESCAPE)
                data.append(self.ESC_9D)
            elif byte == self.ESCAPE:
                data.append(self.ESCAPE)
                data.append(self.ESC_9E)
            else:
                data.append(byte)

        escape_and_append(pkg.from_port)
        send_crc = self._Crc_table[send_crc ^ pkg.from_port]
        escape_and_append(pkg.to_port)
        send_crc = self._Crc_table[send_crc ^ pkg.to_port]
        escape_and_append(pkg.remote_addr & 0xFF)
        send_crc = self._Crc_table[send_crc ^ (pkg.remote_addr & 0xFF)]
        escape_and_append((pkg.remote_addr >> 8) & 0xFF)
        send_crc = self._Crc_table[send_crc ^ ((pkg.remote_addr >> 8) & 0xFF)]
        if pkg.datas:
            for byte in pkg.datas:
                escape_and_append(byte)
                send_crc = self._Crc_table[send_crc ^ byte]
                pass
            pass
                
        escape_and_append(send_crc)
        data.append(self.SEPARATOR)
        return bytes(data)
    
    def receive(self, data: bytes) -> None:
        for byte in data:
            self._receiveByte(byte)
            
    def _receiveByte(self, byte: int) -> None:
        if self._recv_in_esc:
            self._recv_in_esc = False
            if byte == self.ESC_9D:
                self._recv_buffer.append(self.SEPARATOR)
            elif byte == self.ESC_9E:
                self._recv_buffer.append(self.ESCAPE)
            else:
                self._printd(f"接收到未知的转义字符: {byte}")
        else:
            if byte == self.ESCAPE:
                self._recv_in_esc = True
            elif byte == self.SEPARATOR:
                self._receiveEnd()
            else:
                self._recv_buffer.append(byte)
    def _receiveEnd(self) -> None:
        if len(self._recv_buffer) < self.MAC_SIZE:
            self._printd(f"接收到的数据长度不足: {len(self._recv_buffer)}")
            self._recv_buffer.clear()
            return
        recv_crc = 0xff
        for byte in self._recv_buffer[:-1]:
            recv_crc = self._Crc_table[recv_crc ^ byte]
        if recv_crc != self._recv_buffer[-1]:
            self._printd(f"接收到的数据 CRC 错误: {recv_crc} != {self._recv_buffer[-1]}")
            self._recv_buffer.clear()
            return
        from_port = self._recv_buffer[0]
        to_port = self._recv_buffer[1]
        remote_addr = self._recv_buffer[2] + (self._recv_buffer[3] << 8)
        datas = self._recv_buffer[self.MAC_SIZE-1:-1]
        pkg = sCc9dPkg(from_port=from_port, to_port=to_port, remote_addr=remote_addr)
        pkg.datas = datas
        pkg.asRecv()
        self._recvPkgCB(pkg)  # 调用接收回调函数
        self._recv_buffer.clear()
        return   

if __name__ == "__main__":
    print("***  CC9DProtocolParser 测试  ***")
    def sendByteCB(data: bytes) -> bool:
        hex_output = ' '.join(f'{byte:02x}' for byte in data)
        print(f"接收到的数据 (16进制): {hex_output}")
        return True
    
    def recvPkgCB(pkg: sCc9dPkg) -> None:
        print(f"接收到的数据包: from_port={pkg.from_port}, to_port={pkg.to_port}, remote_addr={pkg.remote_addr}, datas={pkg.datas}")

    # 创建一个 CC9DProtocolParser 实例
    parser = CC9DProtocolParser(sendByteCB,recvPkgCB)

    # 创建一个 sCc9dPkg 实例
    pkg = sCc9dPkg(
        from_port=0x01,
        to_port=0x02,
        remote_addr=0x1234,
        datas=bytes([0x10, 0x20, 0x30, 0x40])
    )
    # 调用 send 方法发送数据
    parser.send(pkg)
    # 调用 receive 方法接收数据
    parser.receive(b'\x9d\x9d\x01\x02\x34\x12\x10\x20\x30\x40\xe7\x9d')
    

    print("\n*** 测试 fromCode 方法 ***")
    
    # 测试成功案例
    test_cases = [
        ("000C.112: 12 23 A1 56 /H |255", "基本测试"),
        ("FFFF.5: 01 02 03", "广播地址"),
        ("FFF0.10: |120 |65 |66", "十进制数据"),
        ("1234.20: w65535 q4294967295", "宽字节数据"),
        ("5678.30: /A /B /C", "ASCII字符"),
        ("ABCD.40: $Hello World!", "$ASCII字符串")
    ]
    for code, desc in test_cases:
        result = sCc9dPkg.fromCode(10, code)
        if isinstance(result, str):
            print(f"❌ {desc}失败: {result}")
        else:
            print(f"✅ {desc}成功: {result}")
    
    # 测试错误案例
    error_cases = [
        (101, "000C.112: 12 34", "端口超出范围"),
        (10, "000C 112: 12 34", "缺少分隔符'.'"),
        (10, "000C.112 12 34", "缺少分隔符':'"),
        (10, "FFFFF.112: 12 34", "地址超出范围"),
        (10, "000C.200: 12 34", "目标端口超出范围"),
        (10, "000C.112: |300", "十进制值超出范围"),
        (10, "000C.112: /AB", "ASCII码格式错误"),
        (10, "ABCD.40: $你好世界", "$字符串含非ASCII字符"),
        (10, "5678.30: /你", "/格式含非ASCII字符")
    ]
    for port, code, desc in error_cases:
        result = sCc9dPkg.fromCode(port, code)
        if isinstance(result, str):
            print(f"✅ 预期错误({desc}): {result}")
        else:
            print(f"❌ 意外成功({desc})，应该返回错误")
    
    # 测试实际应用
    print("\n*** 测试在实际应用中使用fromCode ***")
    def sendByteCB(data: bytes) -> bool:
        hex_output = ' '.join(f'{byte:02x}' for byte in data)
        print(f"发送的数据: {hex_output}")
        return True
    
    def recvPkgCB(pkg: sCc9dPkg) -> None:
        print(f"接收到的包: {pkg}")
    
    parser = CC9DProtocolParser(sendByteCB, recvPkgCB)
    
    # 使用fromCode创建包并发送
    result = sCc9dPkg.fromCode(15, "1234.25: 01 02 03 04 /A /B")
    if isinstance(result, str):
        print(f"创建包失败: {result}")
    else:
        print(f"创建的包: {result}")
        parser.send(result)
    
    
    
